#ifndef _CTYPE_H
#define _CTYPE_H

// 每个ascii码具体的属性
#define _U	0x01	/* upper，是否大写字符 */
#define _L	0x02	/* lower，理否小写字符 */
#define _D	0x04	/* digit，是否数字 */
#define _C	0x08	/* cntrl，是否控制字符*/
#define _P	0x10	/* punct 是否是标点符号字符,*/
#define _S	0x20	/* white space (space/lf/tab)，是否空白符 */
#define _X	0x40	/* hex digit，是否十六进制数字 */
#define _SP	0x80	/* hard space (0x20)，是否真的空格？ */

// 查表用的
extern unsigned char _ctype[];
extern char _ctmp;

// 各种判断字符属性的宏
// 方法是查表获得该字符的属性，然后取判断相应的标志位是否置1
// _ctype表中的第0项用于放置EOF，从1项才对应ascii码0，所以下面使用了ctyple+1个哦获取字符属性
#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D))       // 是否字母和数字，取字符然后判断标志位
#define isalpha(c) ((_ctype+1)[c]&(_U|_L))          // 是否字母
#define iscntrl(c) ((_ctype+1)[c]&(_C))             // 控制字符
#define isdigit(c) ((_ctype+1)[c]&(_D))             // 数字
#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D))
#define islower(c) ((_ctype+1)[c]&(_L))
#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP))
#define ispunct(c) ((_ctype+1)[c]&(_P))
#define isspace(c) ((_ctype+1)[c]&(_S))             // 
#define isupper(c) ((_ctype+1)[c]&(_U))
#define isxdigit(c) ((_ctype+1)[c]&(_D|_X))

// 是否是ascii码：> 0x80的不算
#define isascii(c) (((unsigned) c)<=0x7f)
#define toascii(c) (((unsigned) c)&0x7f)

// 大小写转换
// 以tolower(c)为例，先将_ctmp=c, 判断是否大写
// 如果为大写，则将ctmp - A + 'a', 即为ctmp - (A - a)
#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp)
// 原理同上
#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp)

#endif
